#pragma once

#include "Util.hpp"
#include "Protocol.hpp"
#include <unordered_map>
#include <functional>

/*
实现各种服务器上的服务
*/

Response calculator(const Request& req);

// 实现网络上的计算机服务
// 建立一次连接后, 就需要一直计算, 除非客户端主动断开连接
void net_calculate(int sock, const std::string& ip, uint16_t port)
{
    // 对方可能无法一次性将整条数据完整的发送过来, 所以没有读完完整的报文的时候只能继续等待
    if (!(sock >= 0 && !ip.empty() && port >= 1024))
        std::cout << "arguments error " << std::endl;
    

    std::string rdmsg;
    while (true)
    {
        Request req;
        char buf[256];   
        ssize_t actual = read(sock, buf, sizeof(buf) - 1);
        if (actual == 0) // 客户端不写了
        {
            logMsg(NOTICE, "client[%s:%d] interrupt", ip.c_str(), port);
            break;
        }
        else if (actual < 0)
        {
            logMsg(WARNING, "Service.hpp --- %s read error: %s", __LINE__, strerror(errno));
            break;
        }
        // 至此都是读取成功
        buf[actual] = '\0';
        rdmsg += buf;
        // 1. 然后检查是否有了一个完整的请求
        int packageLen = 0;
        //    将这个请求解密
        std::string package = decode(rdmsg, &packageLen); 
        if (packageLen == 0)
        {   // 说明还没有长度, 这个数据报还是不完整的
            continue ;
        }
        // 2. 否则已经有长度了, 这个数据报已经是完整的了, 那么就进行反序列化
        cout << "解密后的请求：" << package << endl;
        if (req.deserialize(package))
        {   // 3. 计算后并返回 Response 结果
            req.debug();
            Response resp = calculator(req);
            // 4. 对响应进行序列化
            std::string respPackage;
            resp.serialize(&respPackage);
            resp.debug();
            // 5. 再对序列化的结果加上一些报头/处理
            respPackage = encode(respPackage, respPackage.size());
            cout << respPackage << endl;
            // 6. 发送数据
            write(sock, respPackage.c_str(), respPackage.size());
        }
    }

}

// 列表初始化
unordered_map<char, function<int(int, int)>> opMap = 
{
    {'+', [](int x, int y) {return x + y;}},
    {'-', [](int x, int y) {return x - y;}},
    {'*', [](int x, int y) {return x * y;}},
    {'/', [](int x, int y) {return x / y;}},
    {'%', [](int x, int y) {return x % y;}}
};


Response calculator(const Request& req)
{
    Response resp;
    if ((req.op_ == '%' || req.op_ == '/') && req.rightop_ == 0)
    {
        resp.exitcode_ = 1; // 除 0 或者 模 0 异常就是 1 错误码
        return resp;
    }

    if (opMap.count(req.op_) == 0)
    {
        resp.exitcode_ = -2; // 没有这个算术符
    }
    
    resp.result_ = opMap[req.op_](req.leftop_, req.rightop_);
    cout << "计算完成" << endl;
    return resp;
}
